#pragma once

#include "../libs/libdef.h"

#include <unordered_set>
#include <unordered_map>
#include <random>

namespace lukv {

template<typename T>
const T& min(const T& a, const T& b) {
    return a < b ? a : b;
}

template<typename T>
const T & max(const T & a, const T & b) {
    return a > b ? a : b;
}

template<typename ... Args>
inline void close_fds(int fd, Args ... args) {
    close(fd);
    if constexpr (sizeof...(args) > 0) {
        close_fds(args...);
    }
}

template<typename T, typename ... Args>
inline void println(T && x, Args ... args) {
    std::cout << x;
    if constexpr (sizeof...(args) > 0) {
        println(args...);
    }
    else {
        std::cout << std::endl;
    }
}

template<typename T, typename ... Args>
inline void print(T && x, Args ... args) {
    std::cout << x;
    if constexpr (sizeof...(args) > 0) {
        println(args...);
    }
}


static std::vector<std::string> split_by_spaces(const std::string & _str) {
    std::vector<std::string> ans;
    auto len = _str.size();
    size_t j = 0;
    for (auto i = 0; i < len; ++i) {
        while (i < len && _str[i] == ' ') ++i;
        j = i;
        while (i < len && _str[i] != ' ') ++i;
        if (j < len) ans.push_back(_str.substr(j, i - j));
    }
    return ans;
}

static std::vector<std::string> split_by_char(const std::string & _str, const char ch) {
    std::vector<std::string> ans;
    auto len = _str.size();
    size_t j = 0;
    for (auto i = 0; i < len; ++i) {
        if (_str[i] == ch) {
            ans.emplace_back(_str.substr(j, i - j));
            j = i + 1;
        }
    }
    if (j < _str.size() - 1) {
        ans.emplace_back(_str.substr(j));
    }
    return ans;
}

static std::vector<int> random_ints_unique(int l, int r, int cnt) {
    static std::default_random_engine e;
    static std::uniform_int_distribution<int> u(l, r);
    std::unordered_set<int> st;
    for (auto i = 0; i < cnt; ++i) {
        int tmp = u(e);
        st.insert(tmp);
        if (st.size() == cnt) break;
    }
    std::vector<int> ans(st.begin(), st.end());
    return ans;
}

static void set_fd_noblk(int fd) {
    int tmp_flag = -1;
    if ((tmp_flag = fcntl(fd, F_GETFL)) < 0) {
        LOG_ERR("F_GETFL FAILED");
        return;
    }
    if (fcntl(fd, F_SETFL, tmp_flag | O_NONBLOCK) < 0) {
        LOG_ERR("F_SETFL O_NONBLOCK FAILED");
    }
}

}